package com.hongji.lms5xxcommunicator.grid.update;

import com.hongji.lms5xxcommunicator.grid.core.RasterState;

/**
 * <p>
 * “均值合并”更新策略：所有命中同一格的点，直接累加求和并计数，
 * 最终计算该格的算术平均值作为 {@link RasterState#meanZ}。
 * </p>
 *
 * <p><b>职责</b></p>
 * <ul>
 *   <li>将一批点累积写入 {@link RasterState#sumZ} 与 {@link RasterState#count}。</li>
 *   <li>更新格的 {@link RasterState#meanZ} 与 {@link RasterState#hasData}。</li>
 *   <li>不区分单点 / 多点，均采用算术平均。</li>
 * </ul>
 *
 * <p><b>用法</b></p>
 * <ol>
 *   <li>调用 {@link #apply(RasterState, double[], double[], double[])}，传入一帧点云。</li>
 *   <li>点的 (x,y) 会映射到栅格行列 (r,c)。</li>
 *   <li>方法会就地更新 {@link RasterState} 内部数组。</li>
 * </ol>
 *
 * @see UpdateStrategy
 * @see ReplaceSingleElseMeanStrategy
 * @see RasterState
 */
public class MeanUpdateStrategy implements UpdateStrategy {

    /**
     * <p>将一批点按“均值合并”方式应用到 {@link RasterState}。</p>
     *
     * <p><b>步骤</b></p>
     * <ol>
     *   <li>逐点累加：对每个点 (x,y,z)，找到对应 (r,c)，累加到 {@link RasterState#sumZ} 与 {@link RasterState#count}。</li>
     *   <li>逐格更新：对有数据的格，计算均值并标记 {@link RasterState#hasData}。</li>
     * </ol>
     *
     * <p><b>边界与健壮性</b></p>
     * <ul>
     *   <li>输入数组为空或长度不一致时直接返回。</li>
     *   <li>越界点通过 {@link RasterState#inBounds(int, int)} 过滤。</li>
     *   <li>跳过 {@code NaN}/{@code Infinity} 值。</li>
     * </ul>
     *
     * @param s   目标栅格状态（不可为 {@code null}）
     * @param xs  点集 X 坐标数组
     * @param ys  点集 Y 坐标数组
     * @param zs  点集 Z 坐标数组
     */
    @Override
    public void apply(RasterState s, double[] xs, double[] ys, double[] zs) {
        if (s == null || xs == null || ys == null || zs == null) return;
        if (xs.length != ys.length || xs.length != zs.length) return;

        final int rows = s.spec.rows;
        final int cols = s.spec.cols;

        // 1) 逐点累加
        for (int i = 0; i < xs.length; i++) {
            final double x = xs[i];
            final double y = ys[i];
            final double z = zs[i];

            if (Double.isNaN(x) || Double.isNaN(y) || Double.isNaN(z)) continue;
            if (Double.isInfinite(x) || Double.isInfinite(y) || Double.isInfinite(z)) continue;

            final int r = s.spec.toRow(y);
            final int c = s.spec.toCol(x);
            if (!s.inBounds(r, c)) continue;

            s.sumZ[r][c] += z;
            s.count[r][c] += 1;
        }

        // 2) 逐格更新均值
        for (int r = 0; r < rows; r++) {
            final double[] sumRow = s.sumZ[r];
            final int[]    cntRow = s.count[r];
            final double[] meanRow = s.meanZ[r];
            final boolean[] hasRow = s.hasData[r];

            for (int c = 0; c < cols; c++) {
                final int cnt = cntRow[c];
                if (cnt > 0) {
                    meanRow[c] = sumRow[c] / cnt; // cnt 恒 > 0
                    hasRow[c] = true;
                }
            }
        }
    }
}
